/**
 * Copyright 2005 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.edi.utils
{
	import mx.formatters.DateFormatter;
	
	/**
	 * 时间工具类
	 * @version v1.0
	 * 
	 */	
	public class BOPDateUtils
	{
		public static const MONTHS_PER_YEAR:int=12;
		public static const DAYS_PER_WEEK:int=7;
		public static const HOURS_PER_DAY:int=24;
		public static const MINUTES_PER_HOUR:int=60;
		public static const SECONDS_PER_MINUTE:int=60;

		public static const MILLIS_PER_SECOND:int=1000;
		public static const MILLIS_PER_MINUTE:int=SECONDS_PER_MINUTE * MILLIS_PER_SECOND;
		public static const MILLIS_PER_HOUR:int=MINUTES_PER_HOUR * MILLIS_PER_MINUTE;
		public static const MILLIS_PER_DAY:int=HOURS_PER_DAY * MILLIS_PER_HOUR;
 

		private static const NOT_NULL_ASSERTION_MESSAGE:String="时间不可为空!";
		private static const GMT_TIMEZONE_STRING:String="GMT";

		/**
		 * 判断两个日期(年月日)是否为同一天 
		 * @param date1
		 * @param date2
		 * @return 相等返回true,否则返回false.
		 * 
		 */		
		public static function isSameDay(date1:Date, date2:Date):Boolean {
			Assert.notNull(date1, NOT_NULL_ASSERTION_MESSAGE);
			Assert.notNull(date2, NOT_NULL_ASSERTION_MESSAGE);

			var result:Boolean=false;
			if (date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate())
				result=true;

			return result;
		}
		/**
		 * 判断两个日期(年月日时分秒)是否为同一时间  
		 * @param date1
		 * @param date2
		 * @return 相等返回true,否则返回false.
		 * 
		 */		
		public static function isSameInstant(date1:Date, date2:Date):Boolean {
			Assert.notNull(date1, NOT_NULL_ASSERTION_MESSAGE);
			Assert.notNull(date2, NOT_NULL_ASSERTION_MESSAGE);

			var result:Boolean=false;
			if (date1.getTime() == date2.getTime())
				result=true;

			return result;
		}


		/**
		 * 在某日期前加上年份. 
		 * @param date
		 * @param years
		 * @return Date
		 * 
		 */		
		public static function addYears(date:Date, years:Number):Date {
			return addMonths(date, years * MONTHS_PER_YEAR);
		}
		
		/**
		 * 在某日期前加上月份. 
		 * @param date
		 * @param months
		 * @return 
		 * 
		 */		
		public static function addMonths(date:Date, months:Number):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);

			var result:Date=new Date(date.getTime());
			result.setMonth(date.month + months);
			result=handleShorterMonth(date, result);
			return result;
		}
		
		/**
		 * 在某日期前加上周数.  
		 * @param date
		 * @param weeks
		 * @return 
		 * 
		 */		
		public static function addWeeks(date:Date, weeks:int):Date {
			return addDays(date, weeks * DAYS_PER_WEEK);
		}
		
		/**
		 * 在某日期前加上天数.  
		 * @param date
		 * @param days
		 * @return 
		 * 
		 */		
		public static function addDays(date:Date, days:int):Date {
			var result:Date=add(date, MILLIS_PER_DAY, days);
			return handleDaylightSavingsTime(date, result);
		}
		
		/**
		 * 在某日期前加上小时数.  
		 * @param date
		 * @param hours
		 * @return 
		 * 
		 */		
		public static function addHours(date:Date, hours:int):Date {
			return add(date, MILLIS_PER_HOUR, hours);
		}
		
		/**
		 * 在某日期前加上分钟数.  
		 * @param date
		 * @param minutes
		 * @return 
		 * 
		 */		
		public static function addMinutes(date:Date, minutes:int):Date {
			return add(date, MILLIS_PER_MINUTE, minutes);
		}
		
		/**
		 * 在某日期前加上秒数.   
		 * @param date
		 * @param seconds
		 * @return 
		 * 
		 */		
		public static function addSeconds(date:Date, seconds:int):Date {
			return add(date, MILLIS_PER_SECOND, seconds);
		}
		
		/**
		 * 在某日期前加上毫秒数.   
		 * @param date
		 * @param milliseconds
		 * @return 
		 * 
		 */		
		public static function addMilliseconds(date:Date, milliseconds:int):Date {
			return add(date, 1, milliseconds);
		}
		
		/**
		 * 在某日期前加上多个(num)时间间隔(multiplier).   
		 * @param date
		 * @param multiplier
		 * @param num
		 * @return 
		 * 
		 */		
		private static function add(date:Date, multiplier:int, num:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var resultTime:Number=date.getTime() + multiplier * num;
			return new Date(resultTime);
		}

		/**
		 * 设置某日期年份. 
		 * @param date
		 * @param year
		 * @return 
		 * 
		 */		
		public static function setYear(date:Date, year:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var result:Date=new Date(year, date.month, date.date, date.hours, date.minutes, date.seconds, date.milliseconds);
			return handleShorterMonth(date, result);
		}
		
		/**
		 * 设置某日期月份. 
		 * @param date
		 * @param month
		 * @return 
		 * 
		 */		
		public static function setMonth(date:Date, month:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var result:Date=new Date(date.fullYear, month, date.date, date.hours, date.minutes, date.seconds, date.milliseconds);
			return handleShorterMonth(date, result);
		}
		
		/**
		 * 设置某日期日期. 
		 * @param date
		 * @param day
		 * @return 
		 * 
		 */		
		public static function setDay(date:Date, day:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, day, date.hours, date.minutes, date.seconds, date.milliseconds);
		}
		
		/**
		 * 设置某日期小时. 
		 * @param date
		 * @param hour
		 * @return 
		 * 
		 */		
		public static function setHours(date:Date, hour:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, hour, date.minutes, date.seconds, date.milliseconds);
		}
		
		/**
		 * 设置某日期分钟. 
		 * @param date
		 * @param minute
		 * @return 
		 * 
		 */		
		public static function setMinutes(date:Date, minute:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, date.hours, minute, date.seconds, date.milliseconds);
		}
		
		/**
		 * 设置某日期秒数. 
		 * @param date
		 * @param second
		 * @return 
		 * 
		 */		
		public static function setSeconds(date:Date, second:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, date.hours, date.minutes, second, date.milliseconds);
		}
		
		/**
		 * 设置某日期毫秒数. 
		 * @param date
		 * @param millisecond
		 * @return 
		 * 
		 */		
		public static function setMilliseconds(date:Date, millisecond:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, date.hours, date.minutes, date.seconds, millisecond);
		}


		/**
		 * 获得日期的标准时间. 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getUTCDate(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return getDateForOffset(date, date.getTimezoneOffset());
		}
		
		/**
		 * 将日期以分钟数向后偏移. 
		 * @param date
		 * @param offsetMinutes
		 * @return 
		 * 
		 */		
		public static function getDateForOffset(date:Date, offsetMinutes:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var offsetMilliseconds:Number=offsetMinutes * MILLIS_PER_MINUTE;
			return new Date(date.getTime() + offsetMilliseconds);
		}


		/**
		 * 获得日期当年的1月1日.
		 * @param date
		 * @return 
		 */		
		public static function getStartOfYear(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return getStartOfDay(new Date(date.fullYear, 0, 1));
		}
		
		/**
		 * 获得某日期所在月的第一天的日期. 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getStartOfMonth(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return getStartOfDay(new Date(date.fullYear, date.month, 1));
		}
		
		/**
		 * 获得某日期所在周的第一天的日期 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getStartOfWeek(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return getStartOfDay(new Date(date.fullYear, date.month, date.date - date.day));
		}
		
		/**
		 * 将某日期的小时,分钟,秒数置零. 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getStartOfDay(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, 0, 0, 0, 0);
		}
		
		/**
		 * 将某日期的小时,分钟,秒数置零. ,如将2011-01-01 12:12:14.123 至为  2011-01-01 00:00:00.000
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getUTCStartOfDay(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(Date.UTC(date.fullYearUTC, date.monthUTC, date.dateUTC, 0, 0, 0, 0));
		}

		/**
		 * 获得某日期本年度的最后一天的日期 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getEndOfYear(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return getEndOfDay(new Date(date.fullYear, 11, 31));
		}
		
		/**
		 * 获得某日期本月最后一天的日期. 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getEndOfMonth(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var lastDateOfMonth:Date=getStartOfMonth(date);
			lastDateOfMonth=addMonths(lastDateOfMonth, 1);
			lastDateOfMonth=addDays(lastDateOfMonth, -1);
			return getEndOfDay(new Date(lastDateOfMonth.fullYear, lastDateOfMonth.month, lastDateOfMonth.date));
		}
		
		/**
		 * 获得某日期当前周的第一天的日期. 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getEndOfWeek(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return getEndOfDay(new Date(date.fullYear, date.month, date.date - date.day + 6));
		}
		
		/**
		 * 获得某日期的的时分秒置为本日最后一毫秒,如将2011-01-01 12:12:14.123 至为  2011-01-01 23:59:59.999
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getEndOfDay(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, 23, 59, 59, 999);
		}

		/**
		 * 获得某日期的的时分秒置为本日最后一毫秒,如将2011-01-01 12:12:14.123 至为  2011-01-01 23:59:59.999 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function getUTCEndOfDay(date:Date):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(Date.UTC(date.fullYearUTC, date.monthUTC, date.dateUTC, 23, 59, 59, 999));
		}

		/**
		 * 获得两个日期的天数差值 
		 * @param startDate
		 * @param endDate
		 * @return 
		 * 
		 */		
		public static function getDaysDiff(startDate:Date, endDate:Date):int {
			return getVariableDiff(startDate, endDate, MILLIS_PER_DAY);
		}
		
		/**
		 * 获得两个日期的小时差值 
		 * @param startDate
		 * @param endDate
		 * @return 
		 * 
		 */		
		public static function getHoursDiff(startDate:Date, endDate:Date):int {
			return getVariableDiff(startDate, endDate, MILLIS_PER_HOUR);
		}
		
		/**
		 * 获得两个日期的分钟差值 
		 * @param startDate
		 * @param endDate
		 * @return 
		 * 
		 */		
		public static function getMinutesDiff(startDate:Date, endDate:Date):int {
			return getVariableDiff(startDate, endDate, MILLIS_PER_MINUTE);
		}
		
		
		private static function getVariableDiff (startDate:Date, endDate:Date, millsPer:int) : int {
			Assert.notNull(startDate, NOT_NULL_ASSERTION_MESSAGE);
			Assert.notNull(endDate, NOT_NULL_ASSERTION_MESSAGE);
			var startMillis:Number = startDate.getTime();
			var endMillis:Number = endDate.getTime();
			var dstOffset:Number = (startDate.getTimezoneOffset() - endDate.getTimezoneOffset()) * MILLIS_PER_MINUTE;
			return Math.ceil((endMillis - startMillis + dstOffset) / millsPer);
		}


		/**
		 * 获得本地时区的编码 
		 * @return 
		 * 
		 */		
		public static function getLocalTimeZoneCode():String {
			var dateString:String=new Date().toString();
			var startIndex:int=dateString.indexOf(GMT_TIMEZONE_STRING);
			var endIndex:int=dateString.indexOf(" ", startIndex);

			return dateString.substring(startIndex, endIndex);
		}
		
		/**
		 * 判断该年度是否为闰年 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function isLeapYear(date:Date):Boolean {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return (date.fullYear % 400 == 0) || ((date.fullYear % 4 == 0) && (date.fullYear % 100 != 0));
		}
		
		/**
		 * 判断某日期是否为工作日(周六和周日属于周末,其它属于工作日) 
		 * @param date
		 * @return 
		 * 
		 */		
		public static function isWeekDay(date:Date):Boolean {
			return !(isWeekEnd(date));
		}
		
		/**
		 * 判断某日期是否为周末(周六和周日属于周末,其它属于工作日)  
		 * @param date
		 * @return 
		 * 
		 */		
		public static function isWeekEnd(date:Date):Boolean {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var dayOfWeek:uint=date.day;
			return dayOfWeek == 0 || dayOfWeek == 6;
		}
		
		/**
		 * 获得昨天的日期 
		 * @return 
		 * 
		 */		
		public static function getYesterday():Date {
			var result:Date=new Date();
			result.setDate(result.getDate() - 1);
			return result;
		}
		
		/**
		 * 获得明天的日期 
		 * @return 
		 * 
		 */		
		public static function getTomorrow():Date {
			var result:Date=new Date();
			result.setDate(result.getDate() + 1);
			return result;
		}


		/*
		 * Helper methods
		 */
		private static function handleShorterMonth(originalDate:Date, newDate:Date):Date {
			var result:Date=newDate;
			var originalDayOfMonth:Number=originalDate.getDate();
			if (originalDayOfMonth > result.date) {
				result=addDays(newDate, -(newDate.date));
			}
			return result;
		}

		private static function handleDaylightSavingsTime(originalDate:Date, newDate:Date):Date {
			var result:Date=newDate;
			var originalHours:int=originalDate.hours;
			if (originalHours != result.hours)
				result=addHours(result, -(result.hours - originalHours));
			var originalMinutes:int=originalDate.minutes;
			if (originalMinutes != result.minutes)
				result=addMinutes(result, -(result.minutes - originalMinutes));

			return result;
		}
		
		/**
		 * 获得格式化当前时间为字符串(格式化字符串为YYYY-MM-DD JJ:NN:SS) 
		 * @return 
		 * 
		 */		
		public static function getFormateNow():String{
			var date:Date = new Date();
			var formatter:DateFormatter = new DateFormatter();
			formatter.formatString = "YYYY-MM-DD JJ:NN:SS";
			return formatter.format(date);
		}
		
		/**
		 * 获得格式化当前时间为字符串(格式化字符串为YYYY-MM-DD)  
		 * @return 
		 * 
		 */		
		public static function getFormateShortNow():String{
			var date:Date = new Date();
			var formatter:DateFormatter = new DateFormatter();
			formatter.formatString = "YYYY-MM-DD";
			return formatter.format(date);
		}

	}
}